#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/bitrev.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/file.h>
#include <linux/blkdev.h>
#include <linux/poll.h>
#include <linux/cdev.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include <linux/uio.h>
#include <linux/idr.h>
#include <linux/bsg.h>
#include <linux/slab.h>

#define CCM_CCGR1_BASE 0x020C406C
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04_BASE 0x020E006C
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04_BASE 0x020E02F8
#define GPIO1_DR_BASE    0x0209C000
#define GPIO1_GDIR_BASE  0x0209c004

#define LED_NAME "ledDriver"
#define LED_NUM     1

static void __iomem * CCM_CCGR1;
static void __iomem * IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04;
static void __iomem * IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04;
static void __iomem * GPIO1_DR;
static void __iomem * GPIO1_GDIR;



struct ledDev
{
      dev_t devid;
      int major;
      int minor;
      struct cdev led_cdev;
      struct class *led_class;
};
static struct ledDev led;

static char flag;
static ssize_t led_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{
  u32 reg =0;
  copy_from_user(&flag,buf,1);
  if(flag==0)
  {
      reg = readl(GPIO1_DR);
      reg &= ~(1<<4);
      writel(reg,GPIO1_DR);
  }
  else
  {
      reg = readl(GPIO1_DR);
      reg |= (1<<4);
      writel(reg,GPIO1_DR);
  }
  return 0;
}
static int led_open(struct inode *inode, struct file *filp)
{
  return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
  return 0;
}
static const struct file_operations led_fops =
{
  .write = led_write,
  .open = led_open,
  .owner = THIS_MODULE,
  .release = led_release,
};

/*  __arm_ioremap(phys_addr_t phys_addr, size_t size,
			    unsigned int mtype)*/
static void LED_GPIO_Init(void)
{
  u32 reg = 0;

  CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);
  IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04= ioremap(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04_BASE,4);
  IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04= ioremap(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04_BASE,4);
  GPIO1_DR= ioremap(GPIO1_DR_BASE,4);
  GPIO1_GDIR= ioremap(GPIO1_GDIR_BASE,4);

  //开led时钟
  reg  = readl(CCM_CCGR1);
  reg &=~(3<<26);
  reg |= 3<<26;
  writel(reg,CCM_CCGR1);
  //设置引脚属性
  writel(0x5,IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04);
  writel(0x10b0,IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04);
  //设置GPIO方向
  reg  = readl(GPIO1_GDIR);
  reg |= 1<<4; 
  writel(reg,GPIO1_GDIR);

  writel(0xFFFFFFFF,GPIO1_DR);
}
static void LED_GPIO_DeInit(void)
{ 
  u32 reg=0;

  //恢复引脚属性
  writel(0,IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04);
  writel(0,IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04);
  //恢复GPIO方向
  reg  = readl(GPIO1_GDIR);
  reg &= ~(1<<4); 
  writel(reg,GPIO1_GDIR);
  //清空数据寄存器
  reg  = readl(GPIO1_DR);
  reg &= ~(1<<4); 
  writel(reg,GPIO1_DR);
    //关led时钟
  reg  = readl(CCM_CCGR1);
  reg &=~(3<<26);
  writel(reg,CCM_CCGR1);

  iounmap(CCM_CCGR1);
  iounmap(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04);
  iounmap(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04);
  iounmap(GPIO1_DR);
  iounmap(GPIO1_GDIR);
}
static int __init led_init(void)
{
  int ret=0;
  printk("led挂载\r\n");
  //////////////////////////LED外设初始化/////////////////////
  LED_GPIO_Init();

  /////////////////////////申请设备号/////////////////////////////
  if(led.major)
  {
    led.devid = MKDEV(led.major,led.minor);
    ret=register_chrdev_region(led.devid,LED_NUM,LED_NAME);
    if(ret<0)
      printk("register error!\r\n");
  }
  else
  {
    ret=alloc_chrdev_region(&led.devid,0,LED_NUM,LED_NAME);
    if(ret<0)
      printk("register error!\r\n");
    else
      printk("major:%d\tminor:%d\r\n",MAJOR(led.devid),MINOR(led.devid));
  }
  //////////////////////////添加字符设备////////////////////////////////
  //led.led_cdev.owner = THIS_MODULE;
  cdev_init(&led.led_cdev, &led_fops);
  ret=cdev_add(&led.led_cdev, led.devid, LED_NUM);
  if(ret < 0)
    printk("cdev add error!\r\n");
  ////////////////////////////创建节点////////////////////////////
  led.led_class = class_create(THIS_MODULE, LED_NAME);
  device_create(led.led_class, NULL, led.devid, NULL, LED_NAME);

  return 0;
}
static void __exit led_exit(void)
{
  printk("led卸载\r\n");
  LED_GPIO_DeInit();
  unregister_chrdev_region(led.devid,LED_NUM);
  cdev_del(&led.led_cdev);
  device_destroy(led.led_class,led.devid);
  class_destroy(led.led_class);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_ALIAS("xiao");
